package com.tjc.sliding;

import java.util.ArrayList;
import java.util.List;

public class TimeSlidingWindow {
    private int[] buckets;
    private int capacity;
    private long startMs;
    private long currentTime;
    private long periodMs;
    private long tickMs;

    public TimeSlidingWindow(long startTime, long periodMs, long tickMs) {
        this.periodMs = periodMs;
        this.tickMs = tickMs;
        this.startMs = startTime - (startTime % tickMs);
        this.currentTime = startMs;
        this.capacity = (int) (periodMs / tickMs) + 1;
        this.buckets = new int[capacity];
    }

    public synchronized int totalCount() {
        int count = 0;
        int index = getIndex() + 2;
        for (int i = 0; i < capacity - 1; i++) {
            count += buckets[(index + i) % capacity];
        }
        return count;
    }

    public synchronized void advance(long timeMs) {
        if (timeMs >= currentTime + tickMs) {
            this.currentTime = timeMs - (timeMs % tickMs);
        }
    }

    public synchronized int getIndex() {
        long virtualId = currentTime / tickMs;
        int index = (int) (virtualId % capacity);
        return index;
    }

    public synchronized int getWithMapping(int index) {
        int id = index;
        if (index < 0) {
            id = capacity + index;
        }
        return buckets[id];
    }

    private int getMappingIndex(int i) {
        return (i) % capacity;
    }

    public synchronized List<Integer> effectiveList() {
        int i = getMappingIndex(getIndex() + 1);
        List<Integer> list = new ArrayList<>();
        for (int j = 0; j < capacity; j++) {
            if (j == i) {
                continue;
            }
            list.add(buckets[j]);
        }
        return list;
    }


    public synchronized int get() {
        return buckets[getIndex()];
    }

    public synchronized void clearExpiredBucket() {
        buckets[(getIndex() + 1) % capacity] = 0;
    }

    public synchronized void set(int count) {
        buckets[getIndex()] = count;
    }

    public synchronized void add(int count) {
        buckets[getIndex()] += count;
    }

    public long currentTime() {
        return currentTime;
    }
}
